﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Pittypat
{
    /// <summary>
    /// <see cref="DataModel"/> 对象的集合。该集合转换为 JSON 时被转换为对象的数组。
    /// </summary>
    /// <typeparam name="T">集合元素的类型，必须是一个具有公共无参构造函数的、可实例化的 <see cref="DataModel"/> 的一个子类。</typeparam>
    /// <remarks>
    /// <para>DataList 用于从数据库结果集合中接收数据对象，并转换为 JSON 对象的数组发送给客户端。</para>
    /// <para>对集合中元素的查找等支持，可以使用 Enumerable 中提供的扩展方法。</para>
    /// </remarks>
    public class DataList<T> : List<T>, IComplex
        where T : DataModel, new()
    {
        /// <summary>
        /// 使用集合的初始容量初始化 DataList 类的新实例。默认容量 20。
        /// </summary>
        /// <param name="capacity">集合的初始容量，如果没有提供，或者小于 1，使用默认容量 20。</param>
        public DataList(int capacity = 20)
            : base(capacity <= 0 ? 20 : capacity)
        {
        }

        /// <summary>
        /// 将集合中的所有 <see cref="DataModel"/> 对象作为 JSON 字符串写入指定的文本流。
        /// </summary>
        /// <param name="writer">目标文本流。</param>
        /// <exception cref="ArgumentNullException">writer 是 null。</exception>
        /// <remarks>
        /// 写入的结果是一个 JSON 对象的数组，数组的每一个元素都是当前集合中每一个 <see cref="DataModel"/> 对象实例转换的 JSON 对象。
        /// </remarks>
        public void Write(TextWriter writer)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            writer.Write("[");

            // 集合中元素数目
            int count = this.Count;

            if (count > 0)
            {
                // 第一个对象元素
                if (this[0] == null)
                {
                    writer.Write("null");
                }
                else
                {
                    this[0].Write(writer);
                }

                // 其他对象元素
                if (count > 1)
                {
                    for (int i = 1; i < count; ++i)
                    {
                        writer.Write(',');
                        if (this[i] == null)
                        {
                            writer.Write("null");
                        }
                        else
                        {
                            this[i].Write(writer);
                        }
                    }
                }
            }

            writer.Write(']');
        }

        /// <summary>
        /// 异步从 DbDataReader 中读取一个或多个对象。不会在内部首先清空集合。
        /// </summary>
        /// <param name="reader">目标 DbDataReader 对象。</param>
        /// <param name="token">用于取消异步操作的标记。</param>
        /// <returns>读取并添加到集合中的对象总数目，如果集合原来不是空的，返回的数目将小于集合元素的数目。</returns>
        /// <exception cref="ArgumentNullException">reader 为空引用。</exception>
        public async Task<int> ReadAsync(DbDataReader reader, CancellationToken token)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            T model = null;
            // 实际读取的对象数目
            int count = 0;

            // 读取下一行数据
            while (await reader.ReadAsync(token))
            {
                // 创建一个新的对象
                model = new T();

                // 从 DataReader 中读取对象本身
                model.Read(reader);

                // 将新对象添加到集合中
                this.Add(model);

                // 增加计数
                ++count;
            }
            
            // 返回实际读取的对象数目
            return count;
        }

        /// <summary>
        /// 将当前集合转换为 JSON 的字符串格式。
        /// </summary>
        /// <returns>字符串格式的 JSON。</returns>
        public override string ToString()
        {
            using (var writer = new StringWriter())
            {
                this.Write(writer);

                return writer.ToString();
            }
        }
    }
}
